React์ experimental_useSubscription ํ ์ ๋ํ ์ฌ์ธต ๋ถ์. ๊ตฌ๋ ์ฒ๋ฆฌ ์ค๋ฒํค๋, ์ฑ๋ฅ ์ํฅ ๋ฐ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ์ ๋ ๋๋ง์ ์ํ ์ต์ ํ ์ ๋ต์ ํ๊ตฌํฉ๋๋ค.
React experimental_useSubscription: ์ฑ๋ฅ ์ํฅ ์ดํด ๋ฐ ์ํ
React์ experimental_useSubscription ํ
์ ์ปดํฌ๋ํธ ๋ด์์ ์ธ๋ถ ๋ฐ์ดํฐ ์์ค๋ฅผ ๊ตฌ๋
ํ๋ ๊ฐ๋ ฅํ๊ณ ์ ์ธ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ํนํ ์ค์๊ฐ ๋ฐ์ดํฐ๋ ๋ณต์กํ ์ํ๋ฅผ ๋ค๋ฃฐ ๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ๊ด๋ฆฌ๋ฅผ ํฌ๊ฒ ๋จ์ํํ ์ ์์ต๋๋ค. ํ์ง๋ง ๋ค๋ฅธ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ ์ฌ์ ์ธ ์ฑ๋ฅ ์ํฅ์ ๋๋ฐํฉ๋๋ค. ์ด๋ฌํ ์ํฅ์ ์ดํดํ๊ณ ์ ์ ํ ์ต์ ํ ๊ธฐ์ ์ ์ฌ์ฉํ๋ ๊ฒ์ ์ฑ๋ฅ์ด ๋ฐ์ด๋ React ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค.
experimental_useSubscription์ด๋ ๋ฌด์์ธ๊ฐ?
experimental_useSubscription์ ํ์ฌ React์ ์คํ์ API์ ์ผ๋ถ๋ก, ์ปดํฌ๋ํธ๊ฐ ์ธ๋ถ ๋ฐ์ดํฐ ์ ์ฅ์(์: Redux ์คํ ์ด, Zustand ๋๋ ์ฌ์ฉ์ ์ ์ ๋ฐ์ดํฐ ์์ค)๋ฅผ ๊ตฌ๋
ํ๊ณ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋ ์๋์ผ๋ก ๋ค์ ๋ ๋๋ง๋๋๋ก ํ๋ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํตํด ์๋ ๊ตฌ๋
๊ด๋ฆฌ์ ํ์์ฑ์ ์์ ๊ณ ๋ ๊น๋ํ๊ณ ์ ์ธ์ ์ธ ๋ฐ์ดํฐ ๋๊ธฐํ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค. ์ง์์ ์ผ๋ก ์
๋ฐ์ดํธ๋๋ ์ ๋ณด์ ์ปดํฌ๋ํธ๋ฅผ ์ํํ๊ฒ ์ฐ๊ฒฐํ๋ ์ ์ฉ ๋๊ตฌ๋ผ๊ณ ์๊ฐํ ์ ์์ต๋๋ค.
์ด ํ ์ ๋ ๊ฐ์ง ์ฃผ์ ์ธ์๋ฅผ ๋ฐ์ต๋๋ค:
dataSource:subscribe๋ฉ์๋(์ต์ ๋ฒ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ณผ ์ ์๋ ๊ฒ๊ณผ ์ ์ฌ)์getSnapshot๋ฉ์๋๋ฅผ ๊ฐ์ง ๊ฐ์ฒด์ ๋๋ค.subscribe๋ฉ์๋๋ ๋ฐ์ดํฐ ์์ค๊ฐ ๋ณ๊ฒฝ๋ ๋ ํธ์ถ๋ ์ฝ๋ฐฑ์ ์ธ์๋ก ๋ฐ์ต๋๋ค.getSnapshot๋ฉ์๋๋ ๋ฐ์ดํฐ์ ํ์ฌ ๊ฐ์ ๋ฐํํฉ๋๋ค.getSnapshot(์ ํ ์ฌํญ): ๋ฐ์ดํฐ ์์ค์์ ์ปดํฌ๋ํธ์ ํ์ํ ํน์ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ๋ ํจ์์ ๋๋ค. ์ด๋ ์ ์ฒด ๋ฐ์ดํฐ ์์ค๊ฐ ๋ณ๊ฒฝ๋์์ง๋ง ์ปดํฌ๋ํธ์ ํ์ํ ํน์ ๋ฐ์ดํฐ๋ ๋์ผํ๊ฒ ์ ์ง๋ ๋ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค.
๋ค์์ ๊ฐ์์ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ฌ์ฉํ ๊ฐ๋จํ ์ฌ์ฉ ์์์ ๋๋ค:
import { experimental_useSubscription as useSubscription } from 'react';
const myDataSource = {
subscribe(callback) {
// ๋ฐ์ดํฐ ๋ณ๊ฒฝ ๊ตฌ๋
๋ก์ง (์: WebSocket, RxJS ๋ฑ ์ฌ์ฉ)
// ์์: setInterval(() => callback(), 1000); // 1์ด๋ง๋ค ๋ณ๊ฒฝ ์๋ฎฌ๋ ์ด์
},
getSnapshot() {
// ์์ค์์ ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ก์ง
return myData;
}
};
function MyComponent() {
const data = useSubscription(myDataSource);
return (
<div>
<p>๋ฐ์ดํฐ: {data}</p>
</div>
);
}
๊ตฌ๋ ์ฒ๋ฆฌ ์ค๋ฒํค๋: ํต์ฌ ๋ฌธ์
experimental_useSubscription์ ์ฃผ์ ์ฑ๋ฅ ์ฐ๋ ค๋ ๊ตฌ๋
์ฒ๋ฆฌ์ ๊ด๋ จ๋ ์ค๋ฒํค๋์์ ๋น๋กฏ๋ฉ๋๋ค. ๋ฐ์ดํฐ ์์ค๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค subscribe ๋ฉ์๋๋ฅผ ํตํด ๋ฑ๋ก๋ ์ฝ๋ฐฑ์ด ํธ์ถ๋ฉ๋๋ค. ์ด๋ ํ
์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ์ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฐ์์ฑ๊ณผ ์ ๋ฐ์ ์ธ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค. ์ด ์ค๋ฒํค๋๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ์์ผ๋ก ๋ํ๋ ์ ์์ต๋๋ค:
- ๋ ๋๋ง ๋น๋ ์ฆ๊ฐ: ๊ตฌ๋ ์ ๋ณธ์ง์ ์ผ๋ก, ํนํ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ์์ค๊ฐ ๋น ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋ ๋ ๋น๋ฒํ ๋ฆฌ๋ ๋๋ง์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ์ฃผ์ ์์ธ ํ์๊ธฐ ์ปดํฌ๋ํธ๋ฅผ ์๊ฐํด๋ณด์ญ์์ค. ์ง์์ ์ธ ๊ฐ๊ฒฉ ๋ณ๋์ ๊ฑฐ์ ๋์์๋ ๋ฆฌ๋ ๋๋ง์ผ๋ก ์ด์ด์ง ๊ฒ์ ๋๋ค.
- ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง: ํน์ ์ปดํฌ๋ํธ์ ๊ด๋ จ๋ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋์ง ์์๋๋ผ๋, ๋จ์ํ ๊ตฌ๋ ์ ์ฌ์ ํ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ์ฌ ๊ณ์ฐ ๋ญ๋น๋ฅผ ์ด๋ํ ์ ์์ต๋๋ค.
- ๋ฐฐ์น ์ ๋ฐ์ดํธ์ ๋ณต์ก์ฑ: React๋ ๋ฆฌ๋ ๋๋ง์ ์ต์ํํ๊ธฐ ์ํด ์ ๋ฐ์ดํธ๋ฅผ ์ผ๊ด ์ฒ๋ฆฌํ๋ ค๊ณ ํ์ง๋ง, ๊ตฌ๋ ์ ๋น๋๊ธฐ์ ํน์ฑ์ผ๋ก ์ธํด ๋๋๋ก ์ด ์ต์ ํ๊ฐ ๋ฐฉํด๋ฐ์ ์์๋ณด๋ค ๋ ๋ง์ ๊ฐ๋ณ ๋ฆฌ๋ ๋๋ง์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
์ฑ๋ฅ ๋ณ๋ชฉ ํ์ ์๋ณํ๊ธฐ
์ต์ ํ ์ ๋ต์ ๋ํด ์์๋ณด๊ธฐ ์ ์, experimental_useSubscription๊ณผ ๊ด๋ จ๋ ์ ์ฌ์ ์ธ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์์ ์ด์ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์ค๋ช
์
๋๋ค:
1. React ํ๋กํ์ผ๋ฌ
React DevTools์์ ์ฌ์ฉํ ์ ์๋ React ํ๋กํ์ผ๋ฌ๋ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํ๋ ์ฃผ์ ๋๊ตฌ์ ๋๋ค. ์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์์ ์ํํ ์ ์์ต๋๋ค:
- ์ปดํฌ๋ํธ ์ํธ์์ฉ ๊ธฐ๋ก:
experimental_useSubscription์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๊ฐ ํ๋ฐํ ์ฌ์ฉ๋๋ ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋กํ์ผ๋งํฉ๋๋ค. - ๋ ๋ ์๊ฐ ๋ถ์: ์์ฃผ ๋ ๋๋ง๋๊ฑฐ๋ ๋ ๋๋ง์ ์ค๋ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋ ์ปดํฌ๋ํธ๋ฅผ ์๋ณํฉ๋๋ค.
- ๋ฆฌ๋ ๋๋ง์ ์์ธ ์๋ณ: ํ๋กํ์ผ๋ฌ๋ ์ข ์ข ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ๋ ํน์ ๋ฐ์ดํฐ ์์ค ์ ๋ฐ์ดํธ๋ฅผ ์ ํํ ์ฐพ์๋ผ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ ์์ค์ ๋ณ๊ฒฝ์ผ๋ก ์ธํด ์์ฃผ ๋ฆฌ๋ ๋๋ง๋๋ ์ปดํฌ๋ํธ์ ์ธ์ฌํ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ด์ญ์์ค. ๋ฆฌ๋ ๋๋ง์ด ์ค์ ๋ก ํ์ํ์ง(์ฆ, ์ปดํฌ๋ํธ์ props๋ state๊ฐ ํฌ๊ฒ ๋ณ๊ฒฝ๋์๋์ง) ํ์ธํ๊ธฐ ์ํด ์์ธํ ์ดํด๋ณด์ธ์.
2. ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง ๋๊ตฌ
ํ๋ก๋์ ํ๊ฒฝ์์๋ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง ๋๊ตฌ(์: Sentry, New Relic, Datadog) ์ฌ์ฉ์ ๊ณ ๋ คํ์ญ์์ค. ์ด๋ฌํ ๋๊ตฌ๋ ๋ค์์ ๋ํ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํ ์ ์์ต๋๋ค:
- ์ค์ ์ฑ๋ฅ ์งํ: ์ปดํฌ๋ํธ ๋ ๋ ์๊ฐ, ์ํธ์์ฉ ์ง์ฐ ์๊ฐ, ์ ๋ฐ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ์์ฑ๊ณผ ๊ฐ์ ์งํ๋ฅผ ์ถ์ ํฉ๋๋ค.
- ๋๋ฆฐ ์ปดํฌ๋ํธ ์๋ณ: ์ค์ ์๋๋ฆฌ์ค์์ ์ง์์ ์ผ๋ก ์ฑ๋ฅ์ด ์ ํ๋๋ ์ปดํฌ๋ํธ๋ฅผ ์ ํํ ์ฐพ์๋ ๋๋ค.
- ์ฌ์ฉ์ ๊ฒฝํ ์ํฅ: ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋๋ฆฐ ๋ก๋ฉ ์๊ฐ์ด๋ ๋ฐ์ ์๋ ์ํธ์์ฉ๊ณผ ๊ฐ์ด ์ฌ์ฉ์ ๊ฒฝํ์ ์ด๋ค ์ํฅ์ ๋ฏธ์น๋์ง ์ดํดํฉ๋๋ค.
3. ์ฝ๋ ๋ฆฌ๋ทฐ ๋ฐ ์ ์ ๋ถ์
์ฝ๋ ๋ฆฌ๋ทฐ ์ค์๋ experimental_useSubscription์ด ์ด๋ป๊ฒ ์ฌ์ฉ๋๊ณ ์๋์ง ์ธ์ฌํ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ด์ญ์์ค:
- ๊ตฌ๋ ๋ฒ์ ํ๊ฐ: ์ปดํฌ๋ํธ๊ฐ ๋๋ฌด ๊ด๋ฒ์ํ ๋ฐ์ดํฐ ์์ค๋ฅผ ๊ตฌ๋ ํ์ฌ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ๊ณ ์์ง๋ ์์ต๋๊น?
getSnapshot๊ตฌํ ๊ฒํ :getSnapshotํจ์๊ฐ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ถ์ถํ๊ณ ์์ต๋๊น?- ์ ์ฌ์ ์ธ ๊ฒฝ์ ์กฐ๊ฑด ์ฐพ๊ธฐ: ํนํ ๋์์ฑ ๋ ๋๋ง์ ๋ค๋ฃฐ ๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์์ค ์ ๋ฐ์ดํธ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋๋์ง ํ์ธํ์ญ์์ค.
์ ์ ๋ถ์ ๋๊ตฌ(์: ์ ์ ํ ํ๋ฌ๊ทธ์ธ์ด ์๋ ESLint) ๋ํ useCallback ๋๋ useMemo ํ
์ ์์กด์ฑ ๋๋ฝ๊ณผ ๊ฐ์ ์ฝ๋์ ์ ์ฌ์ ์ธ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ์๋ณํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
์ต์ ํ ์ ๋ต: ์ฑ๋ฅ ์ํฅ ์ต์ํ
์ ์ฌ์ ์ธ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํ ํ์๋ experimental_useSubscription์ ์ํฅ์ ์ต์ํํ๊ธฐ ์ํด ์ฌ๋ฌ ์ต์ ํ ์ ๋ต์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
1. getSnapshot์ ์ด์ฉํ ์ ํ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
๊ฐ์ฅ ์ค์ํ ์ต์ ํ ๊ธฐ์ ์ getSnapshot ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ์ ํ์ํ ํน์ ๋ฐ์ดํฐ๋ง ์ถ์ถํ๋ ๊ฒ์
๋๋ค. ์ด๋ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ๋ ๋ฐ ํ์์ ์
๋๋ค. ์ ์ฒด ๋ฐ์ดํฐ ์์ค๋ฅผ ๊ตฌ๋
ํ๋ ๋์ ๋ฐ์ดํฐ์ ๊ด๋ จ ํ์ ์งํฉ๋ง ๊ตฌ๋
ํ์ญ์์ค.
์์:
์ด๋ฆ, ์ด๋ฉ์ผ, ํ๋กํ ์ฌ์ง์ ํฌํจํ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ํ๋ด๋ ๋ฐ์ดํฐ ์์ค๊ฐ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ๋ง์ฝ ํ ์ปดํฌ๋ํธ๊ฐ ์ฌ์ฉ์์ ์ด๋ฆ๋ง ํ์ํด์ผ ํ๋ค๋ฉด, getSnapshot ํจ์๋ ์ด๋ฆ๋ง ์ถ์ถํด์ผ ํฉ๋๋ค:
const userDataSource = {
subscribe(callback) { /* ... */ },
getSnapshot() {
return {
name: "Alice Smith",
email: "alice.smith@example.com",
profilePicture: "/images/alice.jpg"
};
}
};
function NameComponent() {
const name = useSubscription(userDataSource, () => userDataSource.getSnapshot().name);
return <p>์ฌ์ฉ์ ์ด๋ฆ: {name}</p>;
}
์ด ์์์์ NameComponent๋ userDataSource ๊ฐ์ฒด์ ๋ค๋ฅธ ์์ฑ์ด ์
๋ฐ์ดํธ๋๋๋ผ๋ ์ฌ์ฉ์์ ์ด๋ฆ์ด ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ง ๋ค์ ๋ ๋๋ง๋ฉ๋๋ค.
2. useMemo์ useCallback์ ์ฌ์ฉํ ๋ฉ๋ชจ์ด์ ์ด์
๋ฉ๋ชจ์ด์ ์ด์
์ ๋น์ฉ์ด ๋ง์ด ๋๋ ๊ณ์ฐ์ด๋ ํจ์์ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ์ฌ React ์ปดํฌ๋ํธ๋ฅผ ์ต์ ํํ๋ ๊ฐ๋ ฅํ ๊ธฐ์ ์
๋๋ค. useMemo๋ฅผ ์ฌ์ฉํ์ฌ getSnapshot ํจ์์ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ๋ชจ์ด์ฆํ๊ณ , useCallback์ ์ฌ์ฉํ์ฌ subscribe ๋ฉ์๋์ ์ ๋ฌ๋ ์ฝ๋ฐฑ์ ๋ฉ๋ชจ์ด์ฆํ์ญ์์ค.
์์:
import { experimental_useSubscription as useSubscription } from 'react';
import { useCallback, useMemo } from 'react';
const myDataSource = {
subscribe(callback) { /* ... */ },
getSnapshot() {
// ๋น์ฉ์ด ๋ง์ด ๋๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ก์ง
return processData(myData);
}
};
function MyComponent({ prop1, prop2 }) {
const getSnapshot = useCallback(() => {
return myDataSource.getSnapshot();
}, []);
const data = useSubscription(myDataSource, getSnapshot);
const memoizedValue = useMemo(() => {
// ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ๋น์ฉ์ด ๋ง์ด ๋๋ ๊ณ์ฐ
return calculateValue(data, prop1, prop2);
}, [data, prop1, prop2]);
return <div>{memoizedValue}</div>;
}
getSnapshot ํจ์์ ๊ณ์ฐ๋ ๊ฐ์ ๋ฉ๋ชจ์ด์ฆํจ์ผ๋ก์จ, ์์กด์ฑ์ด ๋ณ๊ฒฝ๋์ง ์์์ ๋ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง๊ณผ ๋น์ฉ์ด ๋ง์ด ๋๋ ๊ณ์ฐ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ํ์ํ ๋ ๋ฉ๋ชจ์ด์ฆ๋ ๊ฐ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์
๋ฐ์ดํธ๋๋๋ก useCallback๊ณผ useMemo์ ์์กด์ฑ ๋ฐฐ์ด์ ๊ด๋ จ ์์กด์ฑ์ ํฌํจ์์ผ์ผ ํฉ๋๋ค.
3. ๋๋ฐ์ด์ฑ ๋ฐ ์ค๋กํ๋ง
๋น ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋๋ ๋ฐ์ดํฐ ์์ค(์: ์ผ์ ๋ฐ์ดํฐ, ์ค์๊ฐ ํผ๋)๋ฅผ ๋ค๋ฃฐ ๋, ๋๋ฐ์ด์ฑ๊ณผ ์ค๋กํ๋ง์ ๋ฆฌ๋ ๋๋ง ๋น๋๋ฅผ ์ค์ด๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ๋๋ฐ์ด์ฑ: ๋ง์ง๋ง ์ ๋ฐ์ดํธ ์ดํ ์ผ์ ์๊ฐ์ด ์ง๋ ๋๊น์ง ์ฝ๋ฐฑ ํธ์ถ์ ์ง์ฐ์ํต๋๋ค. ์ด๋ ์ผ์ ๊ธฐ๊ฐ ํ๋์ด ์๋ ํ ์ต์ ๊ฐ๋ง ํ์ํ ๋ ์ ์ฉํฉ๋๋ค.
- ์ค๋กํ๋ง: ํน์ ์๊ฐ ๋ด์ ์ฝ๋ฐฑ์ด ํธ์ถ๋ ์ ์๋ ํ์๋ฅผ ์ ํํฉ๋๋ค. ์ด๋ UI๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ์ ๋ฐ์ดํธํด์ผ ํ์ง๋ง ๋ฐ์ดํฐ ์์ค์ ๋ชจ๋ ์ ๋ฐ์ดํธ๋ง๋ค ํ ํ์๋ ์์ ๋ ์ ์ฉํฉ๋๋ค.
Lodash์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ setTimeout์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ ์ ๊ตฌํ์ ํตํด ๋๋ฐ์ด์ฑ ๋ฐ ์ค๋กํ๋ง์ ๊ตฌํํ ์ ์์ต๋๋ค.
์์ (์ค๋กํ๋ง):
import { experimental_useSubscription as useSubscription } from 'react';
import { useRef, useCallback } from 'react';
function MyComponent() {
const lastUpdate = useRef(0);
const throttledGetSnapshot = useCallback(() => {
const now = Date.now();
if (now - lastUpdate.current > 100) { // ์ต๋ 100ms๋ง๋ค ์
๋ฐ์ดํธ
lastUpdate.current = now;
return myDataSource.getSnapshot();
}
return null; // ๋๋ ๊ธฐ๋ณธ๊ฐ
}, []);
const data = useSubscription(myDataSource, throttledGetSnapshot);
return <div>{data}</div>;
}
์ด ์์๋ getSnapshot ํจ์๊ฐ ์ต๋ 100๋ฐ๋ฆฌ์ด๋ง๋ค ํธ์ถ๋๋๋ก ํ์ฌ ๋ฐ์ดํฐ ์์ค๊ฐ ๋น ๋ฅด๊ฒ ์
๋ฐ์ดํธ๋ ๋ ๊ณผ๋ํ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํฉ๋๋ค.
4. React.memo ํ์ฉ
React.memo๋ ํจ์ํ ์ปดํฌ๋ํธ๋ฅผ ๋ฉ๋ชจ์ด์ฆํ๋ ๊ณ ์ฐจ ์ปดํฌ๋ํธ์
๋๋ค. experimental_useSubscription์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ฅผ React.memo๋ก ๊ฐ์ธ๋ฉด ์ปดํฌ๋ํธ์ props๊ฐ ๋ณ๊ฒฝ๋์ง ์์ ๊ฒฝ์ฐ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
์์:
import React, { experimental_useSubscription as useSubscription, memo } from 'react';
function MyComponent({ prop1, prop2 }) {
const data = useSubscription(myDataSource);
return <div>{data}, {prop1}, {prop2}</div>;
}
export default memo(MyComponent, (prevProps, nextProps) => {
// ์ฌ์ฉ์ ์ ์ ๋น๊ต ๋ก์ง (์ ํ ์ฌํญ)
return prevProps.prop1 === nextProps.prop1 && prevProps.prop2 === nextProps.prop2;
});
์ด ์์์์ MyComponent๋ useSubscription์ ๋ฐ์ดํฐ๊ฐ ์
๋ฐ์ดํธ๋๋๋ผ๋ prop1 ๋๋ prop2๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ง ๋ค์ ๋ ๋๋ง๋ฉ๋๋ค. ์ปดํฌ๋ํธ๊ฐ ์ธ์ ๋ค์ ๋ ๋๋ง๋์ด์ผ ํ๋์ง์ ๋ํ ๋ ์ธ๋ฐํ ์ ์ด๋ฅผ ์ํด React.memo์ ์ฌ์ฉ์ ์ ์ ๋น๊ต ํจ์๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
5. ๋ถ๋ณ์ฑ ๋ฐ ๊ตฌ์กฐ์ ๊ณต์
๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ก ์์ ํ ๋, ๋ถ๋ณ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ฉด ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. ๋ถ๋ณ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ๋ชจ๋ ์์ ์ด ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๋๋ก ๋ณด์ฅํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ์ฝ๊ฒ ๊ฐ์งํ๊ณ ํ์ํ ๋๋ง ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํฉ๋๋ค. Immutable.js๋ Immer์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ React์์ ๋ถ๋ณ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ก ์์ ํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
๊ด๋ จ ๊ฐ๋ ์ธ ๊ตฌ์กฐ์ ๊ณต์ ๋ ๋ณ๊ฒฝ๋์ง ์์ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๋ถ๋ถ์ ์ฌ์ฌ์ฉํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ์ด๋ ์๋ก์ด ๋ถ๋ณ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์ค๋ฒํค๋๋ฅผ ๋์ฑ ์ค์ผ ์ ์์ต๋๋ค.
6. ๋ฐฐ์น ์ ๋ฐ์ดํธ ๋ฐ ์ค์ผ์ค๋ง
React์ ๋ฐฐ์น ์
๋ฐ์ดํธ ๋ฉ์ปค๋์ฆ์ ์ฌ๋ฌ ์ํ ์
๋ฐ์ดํธ๋ฅผ ๋จ์ผ ๋ฆฌ๋ ๋๋ง ์ฃผ๊ธฐ๋ก ์๋ ๊ทธ๋ฃนํํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋น๋๊ธฐ ์
๋ฐ์ดํธ(๊ตฌ๋
์ ์ํด ํธ๋ฆฌ๊ฑฐ๋๋ ๊ฒ๊ณผ ๊ฐ์)๋ ๋๋๋ก ์ด ๋ฉ์ปค๋์ฆ์ ์ฐํํ ์ ์์ต๋๋ค. React๊ฐ ํจ๊ณผ์ ์ผ๋ก ์
๋ฐ์ดํธ๋ฅผ ์ผ๊ด ์ฒ๋ฆฌํ ์ ์๋๋ก requestAnimationFrame์ด๋ setTimeout๊ณผ ๊ฐ์ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ์์ค ์
๋ฐ์ดํธ๊ฐ ์ ์ ํ๊ฒ ์ค์ผ์ค๋ง๋๋๋ก ํ์ญ์์ค.
์์:
const myDataSource = {
subscribe(callback) {
setInterval(() => {
requestAnimationFrame(() => {
callback(); // ๋ค์ ์ ๋๋ฉ์ด์
ํ๋ ์์ ์
๋ฐ์ดํธ ์์ฝ
});
}, 100);
},
getSnapshot() { /* ... */ }
};
7. ๋๊ท๋ชจ ๋ฐ์ดํฐ์ ์ ์ํ ๊ฐ์ํ
๊ตฌ๋ ์ ํตํด ์ ๋ฐ์ดํธ๋๋ ๋๊ท๋ชจ ๋ฐ์ดํฐ์ (์: ๊ธด ํญ๋ชฉ ๋ชฉ๋ก)์ ํ์ํ๋ ๊ฒฝ์ฐ, ๊ฐ์ํ ๊ธฐ์ (์: react-window ๋๋ react-virtualized์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ) ์ฌ์ฉ์ ๊ณ ๋ คํ์ญ์์ค. ๊ฐ์ํ๋ ๋ฐ์ดํฐ์ ์ ๋ณด์ด๋ ๋ถ๋ถ๋ง ๋ ๋๋งํ์ฌ ๋ ๋๋ง ์ค๋ฒํค๋๋ฅผ ํฌ๊ฒ ์ค์ ๋๋ค. ์ฌ์ฉ์๊ฐ ์คํฌ๋กคํ๋ฉด ๋ณด์ด๋ ๋ถ๋ถ์ด ๋์ ์ผ๋ก ์ ๋ฐ์ดํธ๋ฉ๋๋ค.
8. ๋ฐ์ดํฐ ์์ค ์ ๋ฐ์ดํธ ์ต์ํ
์๋ง๋ ๊ฐ์ฅ ์ง์ ์ ์ธ ์ต์ ํ๋ ๋ฐ์ดํฐ ์์ค ์์ฒด์ ์ ๋ฐ์ดํธ ๋น๋์ ๋ฒ์๋ฅผ ์ต์ํํ๋ ๊ฒ์ ๋๋ค. ์ฌ๊ธฐ์๋ ๋ค์์ด ํฌํจ๋ ์ ์์ต๋๋ค:
- ์ ๋ฐ์ดํธ ๋น๋ ์ค์ด๊ธฐ: ๊ฐ๋ฅํ๋ค๋ฉด ๋ฐ์ดํฐ ์์ค๊ฐ ์ ๋ฐ์ดํธ๋ฅผ ํธ์ํ๋ ๋น๋๋ฅผ ์ค์ ๋๋ค.
- ๋ฐ์ดํฐ ์์ค ๋ก์ง ์ต์ ํ: ๋ฐ์ดํฐ ์์ค๊ฐ ํ์ํ ๋๋ง ์ ๋ฐ์ดํธํ๊ณ ์ ๋ฐ์ดํธ๊ฐ ๊ฐ๋ฅํ ํ ํจ์จ์ ์ธ์ง ํ์ธํฉ๋๋ค.
- ์๋ฒ ์ธก์์ ์ ๋ฐ์ดํธ ํํฐ๋ง: ํ์ฌ ์ฌ์ฉ์ ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ํ์ ๊ด๋ จ๋ ์ ๋ฐ์ดํธ๋ง ํด๋ผ์ด์ธํธ๋ก ๋ณด๋ ๋๋ค.
9. Redux ๋๋ ๋ค๋ฅธ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์ ๋ ํฐ ์ฌ์ฉ
Redux(๋๋ ๋ค๋ฅธ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ)์ ํจ๊ป experimental_useSubscription์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, ์
๋ ํฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์
๋ ํฐ๋ ์ ์ญ ์ํ์์ ํน์ ๋ฐ์ดํฐ ์กฐ๊ฐ์ ํ์์ํค๋ ์์ ํจ์์
๋๋ค. ์ด๋ฅผ ํตํด ์ปดํฌ๋ํธ๋ ํ์ํ ๋ฐ์ดํฐ๋ง ๊ตฌ๋
ํ ์ ์์ผ๋ฉฐ, ์ํ์ ๋ค๋ฅธ ๋ถ๋ถ์ด ๋ณ๊ฒฝ๋ ๋ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
์์ (Reselect๋ฅผ ์ฌ์ฉํ Redux):
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
// ์ฌ์ฉ์ ์ด๋ฆ์ ์ถ์ถํ๋ ์
๋ ํฐ
const selectUserName = createSelector(
state => state.user,
user => user.name
);
function NameComponent() {
// useSelector์ ์
๋ ํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ด๋ฆ๋ง ๊ตฌ๋
const userName = useSelector(selectUserName);
return <p>์ฌ์ฉ์ ์ด๋ฆ: {userName}</p>;
}
์
๋ ํฐ๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ, user ๊ฐ์ฒด์ ๋ค๋ฅธ ๋ถ๋ถ์ด ์
๋ฐ์ดํธ๋๋๋ผ๋ NameComponent๋ Redux ์คํ ์ด์ user.name ์์ฑ์ด ๋ณ๊ฒฝ๋ ๋๋ง ๋ค์ ๋ ๋๋ง๋ฉ๋๋ค.
๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๊ณ ๋ ค ์ฌํญ
- ๋ฒค์น๋งํฌ ๋ฐ ํ๋กํ์ผ๋ง: ์ต์ ํ ๊ธฐ์ ์ ๊ตฌํํ๊ธฐ ์ ๊ณผ ํ์ ํญ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฒค์น๋งํฌํ๊ณ ํ๋กํ์ผ๋งํ์ญ์์ค. ์ด๋ ๋ณ๊ฒฝ ์ฌํญ์ด ์ค์ ๋ก ์ฑ๋ฅ์ ํฅ์์ํค๋์ง ํ์ธํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
- ์ ์ง์ ์ต์ ํ: ๊ฐ์ฅ ์ํฅ๋ ฅ ์๋ ์ต์ ํ ๊ธฐ์ (์:
getSnapshot์ ์ด์ฉํ ์ ํ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ)๋ถํฐ ์์ํ์ฌ ํ์์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ธฐ์ ์ ์ ์ง์ ์ผ๋ก ์ ์ฉํ์ญ์์ค. - ๋์ ๊ณ ๋ ค: ์ด๋ค ๊ฒฝ์ฐ์๋
experimental_useSubscription์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ต์ ์ ํด๊ฒฐ์ฑ ์ด ์๋ ์๋ ์์ต๋๋ค. ์ ํต์ ์ธ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๊ธฐ์ ์ด๋ ๋ด์ฅ๋ ๊ตฌ๋ ๋ฉ์ปค๋์ฆ์ด ์๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๊ฐ์ ๋์์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ํ์ํ์ญ์์ค. - ์ต์ ์ ๋ณด ์ ์ง:
experimental_useSubscription์ ์คํ์ ์ธ API์ด๋ฏ๋ก, ํฅํ React ๋ฒ์ ์์ ๋์๊ณผ API๊ฐ ๋ณ๊ฒฝ๋ ์ ์์ต๋๋ค. ์ต์ React ๋ฌธ์ ๋ฐ ์ปค๋ฎค๋ํฐ ํ ๋ก ์ ํตํด ์ต์ ์ ๋ณด๋ฅผ ์ ์งํ์ญ์์ค. - ์ฝ๋ ๋ถํ : ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ, ์ด๊ธฐ ๋ก๋ ์๊ฐ์ ์ค์ด๊ณ ์ ๋ฐ์ ์ธ ์ฑ๋ฅ์ ํฅ์์ํค๊ธฐ ์ํด ์ฝ๋ ๋ถํ ์ ๊ณ ๋ คํ์ญ์์ค. ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์์ ๋ฐ๋ผ ๋ก๋๋๋ ๋ ์์ ์ฒญํฌ๋ก ๋๋๋ ๊ฒ์ ํฌํจํฉ๋๋ค.
๊ฒฐ๋ก
experimental_useSubscription์ React์์ ์ธ๋ถ ๋ฐ์ดํฐ ์์ค๋ฅผ ๊ตฌ๋
ํ๋ ๊ฐ๋ ฅํ๊ณ ํธ๋ฆฌํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ ์ฌ์ ์ธ ์ฑ๋ฅ ์ํฅ์ ์ดํดํ๊ณ ์ ์ ํ ์ต์ ํ ์ ๋ต์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ ํ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ, ๋ฉ๋ชจ์ด์ ์ด์
, ๋๋ฐ์ด์ฑ, ์ค๋กํ๋ง ๋ฐ ๊ธฐํ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ๊ตฌ๋
์ฒ๋ฆฌ ์ค๋ฒํค๋๋ฅผ ์ต์ํํ๊ณ ์ค์๊ฐ ๋ฐ์ดํฐ์ ๋ณต์กํ ์ํ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ์ฑ๋ฅ ์ข์ React ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์ต์ ํ ๋
ธ๋ ฅ์ด ์ค์ ๋ก ์ฑ๋ฅ์ ํฅ์์ํค๋์ง ํ์ธํ๊ธฐ ์ํด ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฒค์น๋งํฌํ๊ณ ํ๋กํ์ผ๋งํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ๊ทธ๋ฆฌ๊ณ experimental_useSubscription์ด ๋ฐ์ ํจ์ ๋ฐ๋ผ React ๋ฌธ์์ ์
๋ฐ์ดํธ์ ํญ์ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ด์ญ์์ค. ์ ์คํ ๊ณํ๊ณผ ๋ถ์ง๋ฐํ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง์ ๊ฒฐํฉํจ์ผ๋ก์จ ์ ํ๋ฆฌ์ผ์ด์
๋ฐ์์ฑ์ ํฌ์ํ์ง ์๊ณ experimental_useSubscription์ ํ์ ํ์ฉํ ์ ์์ต๋๋ค.